package com.rainng.coursesystem.controller;

import com.rainng.coursesystem.dto.PaperDTO;
import com.rainng.coursesystem.dto.QuestionDTO;
import com.rainng.coursesystem.model.FavouriteItem;
import com.rainng.coursesystem.model.PaperItem;
import com.rainng.coursesystem.service.PaperService;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;


@RestController
@RequestMapping("/exam")
public class PaperController {

    @Autowired
    private PaperService paperService;



    @PostMapping("/createPaper")
    public ResponseEntity<String> createPaper(@RequestBody PaperItem paper) {

        try {
            System.out.println("Received PaperItem: " + paper); // 打印接收到的 PaperItem 对象
            System.out.println("courseId: " + paper.getCourseId()); // 打印 courseId 的值
            paperService.createPaper(paper);
            return ResponseEntity.ok("Paper created successfully.");
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Failed to create paper: " + e.getMessage());
        }
    }

    @GetMapping("/listPapersByCourse/{courseId}")
    public ResponseEntity<List<PaperItem>> listPapersByCourse(@PathVariable Long courseId) {
        try {
            List<PaperItem> papers = paperService.listPapersByCourse(courseId);
            return ResponseEntity.ok(papers);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        }
    }

    @GetMapping("/getPaper/{paperId}")
    public ResponseEntity<PaperDTO> getPaper(@PathVariable Integer paperId) {
        try {
            PaperItem paper = paperService.getPaper(paperId);
            if (paper == null) {
                return ResponseEntity.notFound().build();
            }

            PaperDTO paperDTO = new PaperDTO();
            paperDTO.setId(paper.getId());
            paperDTO.setName(paper.getName());
            paperDTO.setDescription(paper.getDescription());


            List<QuestionDTO> questionDTOs = paper.getQuestions().stream()
                    .map(question -> {
                        QuestionDTO questionDTO = new QuestionDTO();
                        questionDTO.setId(question.getId());
                        questionDTO.setType(question.getType());
                        questionDTO.setContent(question.getContent());
                        questionDTO.setOptions(question.getOptions()); // 这里返回打乱后的选项
                        questionDTO.setScore(question.getScore());
                        questionDTO.setAnswer(question.getAnswer());
                        return questionDTO;
                    })
                    .collect(Collectors.toList());

            paperDTO.setQuestions(questionDTOs);


            return ResponseEntity.ok(paperDTO);
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        }
    }


    @DeleteMapping("/deletePaper/{paperId}")
    public ResponseEntity<String> deletePaper(@PathVariable Integer paperId) {
        try {
            paperService.deletePaper(paperId);
            return ResponseEntity.ok("Paper deleted successfully.");
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("Failed to delete paper: " + e.getMessage());
        }
    }
    @PostMapping("/upload")
    public ResponseEntity<String> uploadTest(@RequestParam("file") MultipartFile file) throws IOException {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        UUID newFileId = UUID.randomUUID();
        String currentDir = System.getProperty("user.dir");
        String uploadDir= currentDir + "\\src\\main\\resources";
        Path copyLocation = Paths.get(uploadDir,newFileId.toString() + "_" +file.getOriginalFilename());
        Path processedFilePath = Paths.get(uploadDir, newFileId.toString() + "_processed_" + file.getOriginalFilename());
        Files.createDirectories(copyLocation.getParent());
        Files.copy(file.getInputStream(), copyLocation);// 确保目录存在
        System.out.println(copyLocation);
            Mat image = Imgcodecs.imread(copyLocation.toString());
            Files.deleteIfExists(copyLocation);
            // 转换为灰度图像
            Mat gray = new Mat();
            Imgproc.cvtColor(image, gray, Imgproc.COLOR_BGR2GRAY);
            Imgproc.GaussianBlur(gray, gray, new Size(5, 5), 0);
            // 边缘检测
            Mat edges = new Mat();
            Imgproc.Canny(gray, edges, 50, 150);
            List<MatOfPoint> contours = new ArrayList<>();
            Mat hierarchy = new Mat();
            Imgproc.findContours(edges, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
        double minArea = 1000.0; // 设置面积阈值
        int contourIdx = 0;
        for (MatOfPoint contour : contours) {
            // 计算轮廓的面积
            double area = Imgproc.contourArea(contour);

            // 近似轮廓为多边形
            MatOfPoint2f approx = new MatOfPoint2f();
            Imgproc.approxPolyDP(new MatOfPoint2f(contour.toArray()), approx, Imgproc.arcLength(new MatOfPoint2f(contour.toArray()), true) * 0.02, true);

            // 如果多边形有四个顶点且面积大于阈值，我们认为它是一个矩形
            if (approx.rows() == 4 && area > minArea) {
                // 转换MatOfPoint2f到MatOfPoint
                MatOfPoint approxInt = new MatOfPoint();
                approx.convertTo(approxInt, CvType.CV_32SC2);

                // 画出矩形
                List<MatOfPoint> listOfPoints = new ArrayList<>();
                listOfPoints.add(approxInt);
                Imgproc.polylines(image, listOfPoints, true, new Scalar(0, 255, 0), 2);

                // 保存包含矩形的图像
                String rectImageFileName = newFileId.toString() + "_rect_" + contourIdx + ".jpg";
                Path rectImagePath = Paths.get(uploadDir, rectImageFileName);
                Mat rectImage = new Mat(image, new Rect(approxInt.toArray()[0], approxInt.toArray()[2]));
                Imgcodecs.imwrite(rectImagePath.toString(), rectImage);
                contourIdx++;
            }
        }
            MatOfByte buffer = new MatOfByte();
            Imgcodecs.imwrite(processedFilePath.toString(), image);
            return ResponseEntity.ok("Paper uploaded successfully.");
        }



    @PostMapping("/uploadpaper")
    public ResponseEntity<String> uploadpaper(
            @RequestParam("file") MultipartFile file,
            @RequestParam Integer questionId
            ) {
        try {
            // 使用类加载器获取相对路径下的tessdata目录
            String currentDir = System.getProperty("user.dir");
            String languageDataPath= currentDir + "\\src\\main\\resources";
            Tesseract tesseract = new Tesseract();
            // 设置训练库位置
            tesseract.setDatapath(languageDataPath);
            // 设置语言
            tesseract.setLanguage("chi_sim+eng");
            String result = null;
            String studentAnswer = null;
            String fileName = file.getOriginalFilename();
            try {
                // 注意：这里需要将MultipartFile转换为File
                // MultipartFile转File的一种常见做法是将文件内容写入一个临时File
                File tempFile = File.createTempFile("temp", "."+fileName.substring(fileName.lastIndexOf(".") + 1));
                file.transferTo(tempFile);
                studentAnswer = tesseract.doOCR(tempFile);
               result=paperService.markExam(studentAnswer,questionId);
                // 完成后删除临时文件
                tempFile.delete();
            } catch (Exception e) {
                e.printStackTrace();
                return ResponseEntity.status(500).body("OCR processing failed: " + e.getMessage());
            }
            // 可以在这里处理OCR结果，比如保存到数据库等
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            return ResponseEntity.status(500).body("Failed to publish homework: " + e.getMessage());
        }
    }

    private static BufferedImage toGrayscale(BufferedImage original) {
        BufferedImage grayImage = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
        for (int y = 0; y < original.getHeight(); y++) {
            for (int x = 0; x < original.getWidth(); x++) {
                int rgb = original.getRGB(x, y);
                int gray = (int) (0.299 * (rgb & 0xFF) + 0.587 * ((rgb >> 8) & 0xFF) + 0.114 * ((rgb >> 16) & 0xFF));
                grayImage.setRGB(x, y, new java.awt.Color(gray, gray, gray).getRGB());
            }
        }
        return grayImage;
    }

    private static int[] detectHorizontalLines(BufferedImage image) {
        // 假设水平线的阈值（可以根据实际情况调整）
        int threshold = 50; // 灰度值低于此值的像素视为黑色

        // 存储检测到的水平线的y坐标
        java.util.ArrayList<Integer> lines = new java.util.ArrayList<>();

        for (int y = 0; y < image.getHeight(); y++) {
            boolean isLine = true;
            for (int x = 0; x < image.getWidth(); x++) {
                int pixel = image.getRGB(x, y);
                int gray = (pixel >> 16) & 0xFF; // 仅考虑红色分量（灰度图像中三分量相同）
                if (gray > threshold) {
                    isLine = false;
                    break;
                }
            }
            if (isLine) {
                lines.add(y);
                System.out.println(y);
            }
        }

        // 将ArrayList转换为数组并返回
        int[] result = new int[lines.size()];
        for (int i = 0; i < lines.size(); i++) {
            result[i] = lines.get(i);
        }
        return result;
    }


}